﻿/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtCore/QDateTime>
#include <QtMqtt/QMqttClient>
#include <QtWidgets/QMessageBox>
#include <QtNetwork/QHostInfo>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_client = new QMqttClient(this);
    m_client->setHostname(ui->lineEditHost->text());
    m_client->setPort(ui->spinBoxPort->value());
    m_client->setKeepAlive(ui->spinBoxKeepAlive->value());

    connect(m_client, &QMqttClient::stateChanged, this, &MainWindow::updateLogStateChange);
    connect(m_client, &QMqttClient::disconnected, this, &MainWindow::brokerDisconnected);

    connect(m_client, &QMqttClient::messageReceived, this, [this](const QByteArray &message, const QMqttTopicName &topic) {
        const QString content = QDateTime::currentDateTime().toString(Qt::DefaultLocaleShortDate)
                    + " 主题: "
                    + topic.name()
                    + " 消息: "
                    + message
                    + "\n";
        ui->editLog->insertPlainText(content);
    });

//    connect(m_client, &QMqttClient::pingResponseReceived, this, [this]() {
//        const QString content = QDateTime::currentDateTime().toString()
//                    + QLatin1String(" PingResponse")
//                    + QLatin1Char('\n');
//        ui->editLog->insertPlainText(content);
//    });

    connect(ui->lineEditHost, &QLineEdit::textChanged, m_client, &QMqttClient::setHostname);
    connect(ui->lineEditUsername, &QLineEdit::textChanged, m_client, &QMqttClient::setUsername);
    connect(ui->lineEditClientID, &QLineEdit::textChanged, m_client, &QMqttClient::setClientId);
    connect(ui->lineEditPassword, &QLineEdit::textChanged, m_client, &QMqttClient::setPassword);
    connect(ui->spinBoxPort, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::setClientPort);
    connect(ui->cleanSessionCheckBox, &QCheckBox::stateChanged, m_client, &QMqttClient::setCleanSession);
    connect(ui->spinBoxKeepAlive, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::setKeepAlive);

    ui->QosComboBox->addItem("0");
    ui->QosComboBox->addItem("1");
    ui->QosComboBox->addItem("2");
    ui->QosComboBox->setCurrentIndex(0);
    ui->lineEditClientID->setText(QHostInfo::localHostName());
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_buttonConnect_clicked()
{
    if (m_client->state() == QMqttClient::Disconnected) {
        if (ui->lastWillCheckBox->isChecked())
        {
            m_client->setWillTopic(ui->lineEditTopic->text().toUtf8());
            m_client->setWillQoS(ui->QosComboBox->currentIndex());
            m_client->setWillMessage(ui->lineEditMessage->text().toUtf8());
            m_client->setWillRetain(ui->retainedCheckBox->isChecked());
        }
        ui->lineEditHost->setEnabled(false);
        ui->lineEditUsername->setEnabled(false);
        ui->lineEditPassword->setEnabled(false);
        ui->lineEditClientID->setEnabled(false);
        ui->spinBoxPort->setEnabled(false);
        ui->lastWillCheckBox->setEnabled(false);
        ui->cleanSessionCheckBox->setEnabled(false);
        ui->spinBoxKeepAlive->setEnabled(false);
        ui->buttonConnect->setText(tr("断开"));
        m_client->connectToHost();
    } else {
        ui->lineEditHost->setEnabled(true);
        ui->lineEditUsername->setEnabled(true);
        ui->lineEditPassword->setEnabled(true);
        ui->lineEditClientID->setEnabled(true);
        ui->spinBoxPort->setEnabled(true);
        ui->lastWillCheckBox->setEnabled(true);
        ui->cleanSessionCheckBox->setEnabled(true);
        ui->spinBoxKeepAlive->setEnabled(true);
        ui->buttonConnect->setText(tr("连接"));
        m_client->disconnectFromHost();
    }
}

void MainWindow::updateLogStateChange()
{
    QString content = ui->lineEditHost->text() + " ";

    switch (m_client->state())
    {
    case QMqttClient::Disconnected:
        content += "已断开";
        break;
    case QMqttClient::Connecting:
        content += "正在连接";
        break;
    case QMqttClient::Connected:
        content += "已连接";
        break;
    }

    content += "\n";
    ui->editLog->insertPlainText(content);
}

void MainWindow::brokerDisconnected()
{
    ui->lineEditHost->setEnabled(true);
    ui->lineEditUsername->setEnabled(true);
    ui->lineEditPassword->setEnabled(true);
    ui->lineEditClientID->setEnabled(true);
    ui->spinBoxPort->setEnabled(true);
    ui->lastWillCheckBox->setEnabled(true);
    ui->cleanSessionCheckBox->setEnabled(true);
    ui->spinBoxKeepAlive->setEnabled(true);
    ui->buttonConnect->setText(tr("连接"));
}

void MainWindow::setClientPort(int p)
{
    m_client->setPort(p);
}

void MainWindow::setKeepAlive(int t)
{
    m_client->setKeepAlive(t);
}

void MainWindow::on_buttonPublish_clicked()
{
    if (m_client->publish(ui->lineEditTopic->text(),
                          ui->lineEditMessage->text().toUtf8(),
                          ui->QosComboBox->currentIndex(),
                          ui->retainedCheckBox->isChecked()) == -1)
        QMessageBox::critical(this, QLatin1String("Error"), QLatin1String("Could not publish message"));
}

void MainWindow::on_buttonSubscribe_clicked()
{
    auto topic = ui->lineEditTopic->text();
    auto subscription = m_client->subscribe(topic, ui->QosComboBox->currentIndex());
    if (!subscription) {
        QMessageBox::critical(this, QLatin1String("Error"), QLatin1String("Could not subscribe. Is there a valid connection?"));
        return;
    }
    ui->editLog->insertPlainText("订阅主题"+topic + "\n");
}

void MainWindow::on_clearButton_clicked()
{
    ui->editLog->clear();
}

void MainWindow::on_pushButton_clicked()
{
    ui->editLog->setPlainText("First");
}

void MainWindow::on_editLog_cursorPositionChanged()
{
    ui->editLog->textCursor().movePosition(QTextCursor::End);
    ui->editLog->setTextCursor(ui->editLog->textCursor());
}
